Skip to content

Fix phpstan/phpstan#4296: BleedingEdge: Offset '1234' on array<string, Test>&nonEmpty in isset() does not exist.#5174

Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-kz2bn6x
Open

Fix phpstan/phpstan#4296: BleedingEdge: Offset '1234' on array<string, Test>&nonEmpty in isset() does not exist.#5174
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-kz2bn6x

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

PHPStan incorrectly reported "Offset '1234' on array<string, Test>&nonEmpty in isset() does not exist" when checking a numeric string key against a string-keyed array. This fix ensures the original offset type (before toArrayKey() conversion) is also checked against the array's key type.

Changes

  • src/Type/ArrayType.php: In both hasOffsetValueType() and getOffsetValueType(), added a check that also compares the original offset type (before toArrayKey() conversion) against the array's key type. This prevents numeric string keys like '1234' from being falsely rejected when the array has string keys.
  • tests/PHPStan/Rules/Variables/data/bug-4296.php: New regression test reproducing the issue.
  • tests/PHPStan/Rules/Variables/IssetRuleTest.php: Added testBug4296 method.
  • tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php: Removed false positive expectation for '0' on array<string, string> (same root cause).

Root cause

ArrayType::hasOffsetValueType() calls toArrayKey() on the offset type, which converts numeric strings (e.g., '1234') to their integer equivalents (e.g., 1234) per PHP semantics. The subsequent check $this->getKeyType()->isSuperTypeOf($offsetType) then compares StringType against ConstantIntegerType(1234), which returns no. The fix preserves the original offset type and checks it against the key type as well — since '1234' IS a string and the key type IS string, the offset should not be rejected.

Test

Added tests/PHPStan/Rules/Variables/data/bug-4296.php that reproduces the exact scenario from the issue: building an array<string, Test> via a loop, then checking isset($map[$value]) where $value is the numeric string '1234'. The test expects no errors.

Fixes phpstan/phpstan#4296

… isset()

- In ArrayType::hasOffsetValueType and getOffsetValueType, toArrayKey() converts
  numeric strings like '1234' to integers, losing the original string type info
- Added check against original offset type before toArrayKey() conversion so that
  a string offset on a string-keyed array is not incorrectly rejected
- Updated NonexistentOffsetInArrayDimFetchRuleTest to reflect that '0' on
  array<string, string> is no longer a false positive
- New regression test in tests/PHPStan/Rules/Variables/data/bug-4296.php

Closes phpstan/phpstan#4296
@VincentLanglet
Copy link
Contributor

I'm not sure we should do anything until phpstan/phpstan#6847 is fixed
cf phpstan/phpstan#4296 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants